#include "decoder.h"

#include <QDebug>

extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/pixfmt.h"
#include "libswscale/swscale.h"
}


Decoder::Decoder(QObject *parent): QThread(parent)
{
}

void Decoder::run()
{
    AVFormatContext *pFormatCtx = NULL;//音视频格式上下文  Format I/O context.
    AVCodecContext *pCodecCtx = NULL;//音视频编码器相关信息
    AVCodec *pCodec = NULL;//单种音视频编码器对应一个结构体
    AVFrame *pFrame = NULL, *pFrameRGB = NULL;
    AVPacket *packet = NULL;
    uint8_t *out_buffer = NULL;
    int s32Got_picture;

    avformat_network_init();///初始化FFmpeg 网络模块
    av_register_all();//注册AV模块

    pFormatCtx = avformat_alloc_context();

    AVDictionary *avdic = NULL;
    char transport[]  = "rtsp_transport";
    char transport_value[] = "tcp";
    char max_delay[] = "max_delay";
    char max_delay_value[] = "100";


    int s32Ret = av_dict_set(&avdic, transport, transport_value, 0);
    if(s32Ret < 0) {
        errString(s32Ret);
        return ;
    }
    s32Ret = av_dict_set(&avdic, max_delay, max_delay_value, 0);
    if(s32Ret < 0) {
        errString(s32Ret);
        return ;
    }

    //    char url[] = "rtsp://192.168.0.103/sintel.264";
    char *url = m_url.toLatin1().data();

    //打开一个流
    s32Ret = avformat_open_input(&pFormatCtx, url, NULL, &avdic);
    if(s32Ret) {
        errString(s32Ret);
        return;
    }

    //获取视频流信息
    s32Ret = avformat_find_stream_info(pFormatCtx, NULL);
    if(s32Ret) {
        errString(s32Ret);
        return;
    }

    int videoStreamIndex = -1;
    qDebug() << "stream count:" << pFormatCtx->nb_streams;
    for (int i = 0; i < pFormatCtx->nb_streams; ++i) {
        if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
            videoStreamIndex = i;
        }
    }

    if(videoStreamIndex == -1) {
        qDebug() << "Didn't find a video stream";
        m_runState = -1;
        return;
    }

    pCodecCtx = pFormatCtx->streams[videoStreamIndex]->codec;
    pCodec = avcodec_find_decoder(pCodecCtx->codec_id);//根据编码器ID 来查找编码器
    if(pCodec == NULL) {
        errString(s32Ret);
        return;
    }

    //这些参数都是什么意思
    pCodecCtx->bit_rate = 0;
    pCodecCtx->time_base.num = 1;
    pCodecCtx->time_base.den = 10;
    pCodecCtx->frame_number = 1;

    s32Ret = avcodec_open2(pCodecCtx, pCodec, NULL);
    if(s32Ret) {
        errString(s32Ret);
        return;
    }

    pFrame = av_frame_alloc();
    pFrameRGB = av_frame_alloc();

    SwsContext *image_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
                                                   pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_RGB32,
                                                   SWS_BICUBIC, NULL, NULL, NULL);
    if(image_convert_ctx == NULL) {
        qDebug() << "image_convert_ctx failed" ;
        m_runState = -1;
        return;
    }
    //获取一张图片的大小
    int numBytes = avpicture_get_size(AV_PIX_FMT_RGB32, pCodecCtx->width, pCodecCtx->height);
    //申请内存
    out_buffer = (uint8_t*)av_mallocz(numBytes * sizeof(uint8_t));
    avpicture_fill((AVPicture *) pFrameRGB, out_buffer, AV_PIX_FMT_RGB32,
                   pCodecCtx->width, pCodecCtx->height);

    packet = (AVPacket*)av_mallocz(sizeof(AVPacket));
    s32Ret = av_new_packet(packet, pCodecCtx->width * pCodecCtx->height);
    if(s32Ret) {
        errString(s32Ret);
        return;
    }

#if 1
    while (1) {
        if(av_read_frame(pFormatCtx, packet) < 0) {
            //< 0 on error or end of file.
            break;
        }

        if(packet->stream_index == videoStreamIndex) {
            //如果没有可以解压缩的帧为 got_picture零，否则为非零。
            //Use av_frame_alloc() to get an AVFrame.
            s32Ret = avcodec_decode_video2(pCodecCtx, pFrame, &s32Got_picture, packet);
            if(s32Ret < 0) {
                qDebug() << "decode error. \n";
                m_runState = -1;
                return;
            }

            if(s32Got_picture) {
                /**
            int sws_scale(struct SwsContext *c, const uint8_t *const srcSlice[],
              const int srcStride[], int srcSliceY, int srcSliceH,
              uint8_t *const dst[], const int dstStride[]);
***/
                sws_scale(image_convert_ctx,
                          (uint8_t const * const * )pFrame->data,
                          pFrame->linesize, 0,/*要处理的切片的源图像中的位置，即切片的第一行图像中的数字（从*零开始计数）*/
                          pCodecCtx->height,
                          pFrameRGB->data,
                          pFrameRGB->linesize);

                QImage tmpImg((uint8_t* )out_buffer, pCodecCtx->width, pCodecCtx->height,QImage::Format_RGB32);
                QImage image = tmpImg.copy();//为什么要复制一份呢？
                emit sendFrame(image);
            }
            //需要对 avcodec_decode_video2 创建的AVFrame 进行释放
        }
        av_free_packet(packet);
    }
#endif

    m_runState = 0;

    av_free(out_buffer);
    av_free(pFrameRGB);
    out_buffer = NULL;
    pFrameRGB = NULL;
    avcodec_close(pCodecCtx);
    avformat_close_input(&pFormatCtx);
    avformat_network_deinit();
    sws_freeContext(image_convert_ctx);
}


void Decoder::errString(int s32Ret)
{
    char errStr[100] = {0};
    av_strerror(s32Ret,errStr, sizeof(errStr));
    qDebug() << errStr;

    m_runState = s32Ret;
}


void Decoder::setUrl(QString &url)
{
    m_url = url;
    m_runState = 0;
}
